﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Medianamik.Core;
using Medianamik.Core.DAL;
using Medianamik.Core.DAL.Repositories;
using Medianamik.Core.DAL.Services;
using Medianamik.Core.Interfaces;
using Medianamik.Core.Sugar;
using StructureMap;
using SubSonic;

namespace Medianamik.Client.Data
{
    public interface IFullMedianamikRepository<TCollection, TItem> : 
        IRepositoryWithDefaultFilters<TItem> 
        where TCollection : ICollectionWithChildren<TCollection, TItem>, new() 
        where TItem : IMedianamikDTO, IRecordBase, new()
    {
        TItem Get(Guid nodeId);
        TItem Get(Guid nodeId, CultureInfo culture, ContentState contentState);

        TItem Get(Guid nodeId, CultureInfo culture, ContentState contentState, 
                                  ActiveStatus activeStatus);

        IList<TItem> GetWithFilters(Guid? typeId, Guid? parentId, 
            IEnumerable<Where> wheres, IEnumerable<BetweenAnd> betweensAnd, string orderByString,
            int? depth, bool withTypeInheritance);

        PagedCollection<TItem> PagedWithFilters(int pageIndex, int pageSize,
            Guid? typeId, Guid? parentId, IEnumerable<Where> wheres, 
            IEnumerable<BetweenAnd> betweensAnd,
            string orderByString, int? depth, bool withTypeInheritance);

        IList<TItem> ChildsOf(Guid nodeId, bool inclusive, int maxDepth);
        IList<TItem> ParentsOf(Guid nodeId, bool inclusive, int maxDepth);
        IEnumerable<TItem> LoadByIDs(string ids);
        IEnumerable<TItem> LoadByIDs(IList<Guid> ids);
        IList<TItem> All();

        PagedCollection<TItem> PagedWithFilters(CultureInfo culture, int pageIndex, 
            int pageSize, ActiveStatus status, Guid? typeId, Guid? parentId, DateTime? startDate,
            DateTime? endDate, string keywords, string orderBy, 
            IEnumerable<Where> additionalWheres, bool withTypeInheritance);

        PagedCollection<TItem> PagedWithFilters(bool multiLingual, CultureInfo culture, int pageIndex,
            int pageSize, ActiveStatus status, Guid? typeId, Guid? parentId, DateTime? startDate,
            DateTime? endDate, string keywords, string orderBy,
            IEnumerable<Where> additionalWheres, bool withTypeInheritance);

        PagedCollection<TItem> PagedWithFilters(CultureInfo culture, int pageIndex,
            int pageSize, Guid baseTypeId, Guid moduleNodeId, IEnumerable<Where> additionalWheres);

        IList<TItem> GetWithFilters(CultureInfo culture,
            ContentState contentState, ActiveStatus status,
            Guid? typeId, Guid? parentId, IEnumerable<Where> wheres,
            IEnumerable<BetweenAnd> betweensAnd, string orderByString,
            int? depth, bool withTypeInheritance);

        PagedCollection<TItem> PagedWithFilters(CultureInfo culture,
            ContentState contentState, ActiveStatus status, int pageIndex, int pageSize, Guid? typeId,
            Guid? parentId, IEnumerable<Where> wheres, IEnumerable<BetweenAnd> betweensAnd,
            string orderByString, int? depth, bool withTypeInheritance);

        PagedCollection<TItem> PagedWithFilters(bool multiLingual, CultureInfo culture,
            ContentState contentState, ActiveStatus status, int pageIndex, int pageSize, Guid? typeId,
            Guid? parentId, IEnumerable<Where> wheres, IEnumerable<BetweenAnd> betweensAnd,
            string orderByString, int? depth, bool withTypeInheritance);

        IList<TItem> ChildsOf(Guid nodeId, bool inclusive, int maxDepth,
            CultureInfo culture, ContentState contentState, ActiveStatus status);

        IList<TItem> ParentsOf(Guid nodeId, bool inclusive, int maxDepth,
            CultureInfo culture, ContentState contentState, ActiveStatus status);

        IEnumerable<TItem> LoadByIDs(string ids, string cultureName, ContentState contentState,
            ActiveStatus status);

        IEnumerable<TItem> LoadByIDs(IList<Guid> ids, string cultureName,
            ContentState contentState, ActiveStatus status);

        IList<TItem> All(CultureInfo culture, ContentState contentState,
                                         ActiveStatus status);

        void Reorder(Guid id, Guid destinationId, DropPosition position);
        void SetActiveStatus(Guid id, CultureInfo culture, ActiveStatus status);
        INodeWrapper NewNode(IMedianamikDTO dto);
        INodeWrapper GetExistingNode(IMedianamikDTO dto);
        void SaveNode(INodeWrapper node);
        void PublishNode(INodeWrapper node, CultureInfo culture, DateTime startDate, 
            DateTime? endDate);
        void SaveAndPublishNode(INodeWrapper node, CultureInfo culture, DateTime startDate, 
            DateTime? endDate);
        void SaveNodeHandlingPositionAndParentNodeId(INodeWrapper node, Guid? parentNodeId, 
            short? position);
        void SaveAndPublishNodeHandlingPositionAndParentNodeId(INodeWrapper node, Guid? parentNodeId, 
            short? position, CultureInfo culture, DateTime startDate, DateTime? endDate);
    }

    public class FullMedianamikRepository<TCollection, TItem> : 
        MedianamikRepository<TCollection, TItem>, 
        IFullMedianamikRepository<TCollection, TItem> 
        where TCollection : ICollectionWithChildren<TCollection, TItem>, new()
        where TItem : IMedianamikDTO, IRecordBase, new()
    {
        private readonly ICultureService _cultureService;
        private readonly IContentStateService _contentStateService;

        public FullMedianamikRepository(ICultureService cultureService,
            IContentStateService contentStateService)
        {
            _cultureService = cultureService;
            _contentStateService = contentStateService;
        }

        public FullMedianamikRepository()
            : this(ObjectFactory.GetInstance<ICultureService>(),
            ObjectFactory.GetInstance<IContentStateService>())
        {

        }

        protected ICultureService CultureService
        {
            get { return _cultureService; }
        }

        protected IContentStateService ContentStateService
        {
            get { return _contentStateService; }
        }

        public virtual TItem Get(Guid nodeId)
        {
            return Get(nodeId, CultureService.GetCurrentCulture(), ContentStateService.GetCurrentContentState());
        }
        public override TItem Get(Guid nodeId, CultureInfo culture, ContentState contentState)
        {
            return Get(nodeId, culture, contentState, ActiveStatus.Activated);
        }

        public virtual TItem Get(Guid nodeId, CultureInfo culture, ContentState contentState, 
            ActiveStatus activeStatus)
        {
            return LoadByIDs(new[] { nodeId }.ToList(), culture.Name, contentState,
                activeStatus).FirstOrDefault();
        }

        public virtual IList<TItem> GetWithFilters(Guid? typeId, Guid? parentId, 
            IEnumerable<Where> wheres, IEnumerable<BetweenAnd> betweensAnd, string orderByString,
            int? depth, bool withTypeInheritance)
        {
            return base.GetWithFilters(CultureService.GetCurrentCulture(),
                ContentStateService.GetCurrentContentState(), ActiveStatus.Activated, typeId,
                parentId, wheres, betweensAnd, orderByString, depth, withTypeInheritance);
        }

        public virtual PagedCollection<TItem> PagedWithFilters(int pageIndex, int pageSize,
            Guid? typeId, Guid? parentId, IEnumerable<Where> wheres, 
            IEnumerable<BetweenAnd> betweensAnd,
            string orderByString, int? depth, bool withTypeInheritance)
        {
            return base.PagedWithFilters(CultureService.GetCurrentCulture(),
                 ContentStateService.GetCurrentContentState(), ActiveStatus.Activated,
                 pageIndex, pageSize, typeId, parentId, wheres, betweensAnd, orderByString,
                 depth, withTypeInheritance);
        }

        public virtual IList<TItem> ChildsOf(Guid nodeId, bool inclusive, int maxDepth)
        {
            return base.ChildsOf(nodeId, inclusive, maxDepth, CultureService.GetCurrentCulture(),
                 ContentStateService.GetCurrentContentState(), ActiveStatus.Activated);
        }

        public virtual IList<TItem> ParentsOf(Guid nodeId, bool inclusive, int maxDepth)
        {
            return base.ParentsOf(nodeId, inclusive, maxDepth, CultureService.GetCurrentCulture(),
                 ContentStateService.GetCurrentContentState(), ActiveStatus.Activated);
        }

        public virtual IEnumerable<TItem> LoadByIDs(string ids)
        {
            return LoadByIDs(ids, CultureService.GetCurrentCulture().Name,
                 ContentStateService.GetCurrentContentState(), ActiveStatus.Activated);
        }

        public virtual IEnumerable<TItem> LoadByIDs(IList<Guid> ids)
        {
            return LoadByIDs(ids, CultureService.GetCurrentCulture().Name,
                 ContentStateService.GetCurrentContentState(), ActiveStatus.Activated);
        }

        public virtual IList<TItem> All()
        {
            return base.All(CultureService.GetCurrentCulture(),
                 ContentStateService.GetCurrentContentState(), ActiveStatus.Activated);
        }

        public virtual PagedCollection<TItem> PagedWithFilters(CultureInfo culture, int pageIndex, 
            int pageSize, ActiveStatus status, Guid? typeId, Guid? parentId, DateTime? startDate,
            DateTime? endDate, string keywords, string orderBy, 
            IEnumerable<Where> additionalWheres, bool withTypeInheritance)
        {
            return PagedWithFilters(false, culture, pageIndex,
                                    pageSize, status, typeId, parentId, startDate,
                                    endDate, keywords, orderBy,
                                    additionalWheres, withTypeInheritance);
        }

        public virtual PagedCollection<TItem> PagedWithFilters(bool multiLingual, CultureInfo culture, int pageIndex,
            int pageSize, ActiveStatus status, Guid? typeId, Guid? parentId, DateTime? startDate,
            DateTime? endDate, string keywords, string orderBy,
            IEnumerable<Where> additionalWheres, bool withTypeInheritance)
        {
            var wheres = additionalWheres == null ? new List<Where>() : additionalWheres.ToList();

            if (startDate.HasValue)
            {
                wheres.Add(new Where
                {
                    ColumnName = "CreatedOn",
                    Comparison = Comparison.GreaterOrEquals,
                    ParameterValue = startDate.Value
                });
            }

            if (endDate.HasValue)
            {
                wheres.Add(new Where
                {
                    ColumnName = "CreatedOn",
                    Comparison = Comparison.LessOrEquals,
                    ParameterValue = endDate.Value
                });
            }

            if (!String.IsNullOrEmpty(keywords))
            {
                wheres.Add(new Where
                {
                    ColumnName = "Name",
                    Comparison = Comparison.Like,
                    ParameterValue = '%' + keywords + '%'
                });
            }

            var finalOrderBy = "createdon desc";

            if (!orderBy.IsNullOrEmptyTrim())
                finalOrderBy = orderBy.Trim();

            return base.PagedWithFilters(multiLingual, culture,
                ContentState.Draft, status, pageIndex,
                pageSize, typeId, parentId,
                wheres, null, finalOrderBy, 1, withTypeInheritance);
        }

        public virtual PagedCollection<TItem> PagedWithFilters(CultureInfo culture, int pageIndex,
            int pageSize, Guid baseTypeId, Guid moduleNodeId, IEnumerable<Where> additionalWheres)
        {
            return base.PagedWithFilters(culture,ContentState.Draft, ActiveStatus.Activated,
                pageIndex, pageSize, baseTypeId, moduleNodeId, additionalWheres, null, null, 1, true);
        }
    }
}
